#include "guiterm.hpp"

TerminalLayout::TerminalLayout(QScrollBar *scrollBar)
	:scrollBar(scrollBar)
{
	connect(scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scroll(int)));
	scrollOffset = 0;
	lastElementBottom = 0;
}

TerminalLayout::~TerminalLayout()
{
}

QSize TerminalLayout::sizeHint() const
{
	return QSize(640, 480);
}

QSize TerminalLayout::minimumSize() const
{
	return QSize(120, 80);
}

void TerminalLayout::addItem(QLayoutItem *item)
{
	contents.push_back(item);
}

QLayoutItem *TerminalLayout::itemAt(int index) const
{
	if(index<0 || (size_t)index>=contents.size())
		return NULL;
	return contents[index];
}

QLayoutItem *TerminalLayout::takeAt(int index)
{
	if(index<0 || (size_t)index>=contents.size())
		return NULL;
	deque<QLayoutItem*>::iterator erasedIter = contents.begin()+index;
	QLayoutItem *ret = *erasedIter;
	contents.erase(erasedIter);
	return ret;
}

int TerminalLayout::count() const
{
	return contents.size();
}

void TerminalLayout::setGeometry(const QRect &rect)
{
	QLayout::setGeometry(rect);
	updateScroll(rect);
	placeContents(rect);
}

void TerminalLayout::scroll(int offset)
{
	scrollOffset = offset;
	placeContents(geometry());
}

int TerminalLayout::getItemHeight(QLayoutItem *item, int width)
{
	QWidget *widget = item->widget();
	if(!widget) {
		trace << "Layout item has no widget!\n"; //DEBUG
		return 0;
	}
	
	if(widget) {
		int heightFromWidth = widget->heightForWidth(width);
		if(heightFromWidth>0) {
			return heightFromWidth;
		}
	}
	
	int hintedHeight = item->sizeHint().height();
	if(hintedHeight>0)
		return hintedHeight;
	
	int minimumHeight = item->minimumSize().height();
	if(minimumHeight > 0)
		return minimumHeight;
	
	return 0;
}

void TerminalLayout::updateScroll(const QRect &rect)
{
	int width = rect.width();
	int height = rect.height();
	int y=0;
	int bottom = 0;
	int bottomElementTop = 0;
	for(size_t ii=0; ii<contents.size(); ii++)
	{
		bottomElementTop = y;
		int elementHeight = getItemHeight(contents[ii], width);
		y += elementHeight;
	}
	bottom = y;
	
	int newScrollOffset = scrollOffset;
	// If new stuff has been added to push content off the bottom, and we were
	// scrolled far enough down that the bottom wasn't hidden before, scroll
	// down so the bottom is still not hidden.
	if(scrollOffset+height >= lastElementBottom
	   && scrollOffset+height < bottom)
	{
		newScrollOffset = bottom-height;
	}
	
	scrollBar->setRange(0, bottomElementTop);
	
	if(newScrollOffset != scrollOffset) {
		scrollBar->setValue(newScrollOffset);
	}
	
	lastElementBottom = bottom;
}

void TerminalLayout::placeContents(const QRect &rect)
{
	int y = 0;
	int width = rect.width();
	int bottomElementTop = 0;
	
	for(size_t ii=0; ii<contents.size(); ii++)
	{
		bottomElementTop = y;
		QLayoutItem *item = contents[ii];
		int height = getItemHeight(item, width);
		
		QRect geom(rect.x(), rect.y()+y-scrollOffset, width, height);
		y += height;
		item->setGeometry(geom);
	}
}

